﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
using PDOGenerator.DbToMoreGen;
using PDOGenerator.Generators;
using PDOGenerator.MapTypes;
using PDOGenerator.Util;
using PDOGenerator.Dialogs;

namespace PDOGenerator
{
    public class GeneratorPM : INotifyPropertyChanged
    {
        private Project _project;
        private List<Project> _projectRoot;
        private Dispatcher _dispatcher;

        public GeneratorPM()
        {
            _dispatcher = Dispatcher.CurrentDispatcher;
            _project = new Project();
            _project.ProjectName = "New Project";
            
            _projectRoot = new List<Project>(new Project[] { _project });

            // Commands
            _readDatabaseCommand = new ReadDatabaseCommand(this);
            _generateORMFilesCommand = new GenerateORMFilesCommand(this);
        }

        private double _backgroundFade = 1;
        public double BackgroundFade
        {
            get { return _backgroundFade; }
            set
            {
                _backgroundFade = value;
                OnPropertyChanged("BackgroundFade");
            }
        }


        private string _lastError;
        public string LastError
        {
            get { return _lastError; }
            set { _lastError = value; }
        }

        private string _lastErrorDetails;
        public string LastErrorDetails
        {
            get { return _lastErrorDetails; }
            set { _lastErrorDetails = value; }
        }

        private bool _isBusy;
        public bool IsBusy
        {
            get { return _isBusy; }
            set
            {
                _isBusy = value;
                OnPropertyChanged("IsBusy");

                BackgroundFade = (_isBusy ? 0.5 : 1.0);
            }
        }

        private string _busyMessage;

        public string BusyMessage
        {
            get { return _busyMessage; }
            set
            {
                _busyMessage = value;
                OnPropertyChanged("BusyMessage");
            }
        }

        public void DisplayErrorCollection(string title)
        {
            if (null != LastError)
            {
                if (_dispatcher.CheckAccess())
                {
                    MessageDialog.ShowMessage(title, LastError, LastErrorDetails);
                }
                else
                {
                    Action a = () =>
                    {
                        MessageDialog.ShowMessage(title, LastError, LastErrorDetails);
                    };
                    _dispatcher.Invoke(DispatcherPriority.Normal, a);
                }
            }
        }


        public Project Project
        {
            get { return _project; }
            set
            {
                _project = value;
                OnPropertyChanged("Project");

                _projectRoot = new List<Project>(new Project[] { _project });
                OnPropertyChanged("ProjectRoot");
            }
        }

        public List<Project> ProjectRoot
        {
            get { return _projectRoot; }
        }

        public void LoadDatabaseInfo()
        {
            FromDb gen = new FromDb(_project);
            gen.MergeProject();
        }


        public void Refresh()
        {
            // NOTE: Use GetDefaultView(ProjectRoot).Refresh() instead of OnPropertyChanged("ProjectRoot").
            // OnPropertyChanged() does not trigger refresh of entire tree.

            if (_dispatcher.CheckAccess())
            {
                CollectionViewSource.GetDefaultView(ProjectRoot).Refresh();
            }
            else
            {
                Action a = () => { CollectionViewSource.GetDefaultView(ProjectRoot).Refresh(); };
                _dispatcher.Invoke(DispatcherPriority.Normal, a);
            }
        }

        #region Commands

        #region ReadDatabase

        readonly ICommand _readDatabaseCommand;

        /// <summary>
        /// Returns the command used to execute a search in the family tree.
        /// </summary>
        public ICommand ReadDatabase
        {
            get { return _readDatabaseCommand; }
        }

        private class ReadDatabaseCommand : ICommand
        {
            readonly GeneratorPM _pm;

            public ReadDatabaseCommand(GeneratorPM pm)
            {
                _pm = pm;
            }

            public bool CanExecute(object parameter)
            {
                return true;
            }

            event EventHandler ICommand.CanExecuteChanged
            {
                add { }
                remove { }
            }

            public void Execute(object parameter)
            {
                _pm.LastError = null;
                ThreadPool.QueueUserWorkItem(x =>
                {
                    _pm.IsBusy = true;
                    _pm.BusyMessage = "Retrieving database information.";

                    _pm.LoadDatabaseInfo();
                    _pm.Refresh();

                    _pm.IsBusy = false;

                    _pm.DisplayErrorCollection("Error during load.");
                });

            }
        }

        #endregion // ReadDatabase


        #region GenerateORMFiles

        readonly ICommand _generateORMFilesCommand;

        /// <summary>
        /// Returns the command used to execute a search in the family tree.
        /// </summary>
        public ICommand GenerateORMFiles
        {
            get { return _generateORMFilesCommand; }
        }

        private class GenerateORMFilesCommand : ICommand
        {
            readonly GeneratorPM _pm;

            public GenerateORMFilesCommand(GeneratorPM pm)
            {
                _pm = pm;
            }

            public bool CanExecute(object parameter)
            {
                return true;
            }

            event EventHandler ICommand.CanExecuteChanged
            {
                add { }
                remove { }
            }

            public void Execute(object parameter)
            {
                _pm.LastError = null;

                GenerateDialog dlg = new GenerateDialog(_pm.Project);
                if (dlg.ShowDialog() == true)
                {
                    ThreadPool.QueueUserWorkItem(x =>
                    {
                        try
                        {
                            _pm.IsBusy = true;
                            MasterGenerator.WriteFiles(_pm.Project);
                        }
                        catch (Exception ex)
                        {
                            _pm.LastError = "Error reading database: " + ex.Message;
                            _pm.LastErrorDetails += "\r\n" + ex.ToString();
                        }
                        finally
                        {
                            _pm.IsBusy = false;
                        }
                        _pm.DisplayErrorCollection("Error during generation.");

                    });
                }
            }
        }

        #endregion // GenerateORMFiles

        #endregion // Commands

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            // Property change events cross threading is handled by .Net - no special invokes reauired.
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion // INotifyPropertyChanged Members

    }
}
